#include"program.h"
#include"stdlib.h"
#include"interrupt.h"
#include"stdio.h"
#include"os_modules.h"
#include"thread.h"
#include"asm_utils.h"

const int PCB_SIZE = 4096;  //PCB大小4kb
char PCB_SET[PCB_SIZE*MAX_PROGRAM_AMOUNT];  //存放PCB数组
bool PCB_SET_STATUS[MAX_PROGRAM_AMOUNT];    //PCB的分配状态

ProgramManager::ProgramManager()
{
    initialize();
}
void ProgramManager::initialize()
{
    allPrograms.initialize();
    readyPrograms.initialize();
    running=nullptr;
    for(int i=0; i<MAX_PROGRAM_AMOUNT; i++)
    {
        PCB_SET_STATUS[i]=false;
    }
}
int ProgramManager::executeThread(ThreadFunction function,void* parameter,const char* name,int priority)
{
    //关中断，防止创建线程的过程被打断
    bool status=interruptManager.getInterruptStatus();
    interruptManager.disableInterrupt();
    //分配一页作为PCB
    PCB* thread=allocatePCB();
    if(!thread)return -1;
    memset(thread,0,PCB_SIZE);
    for(int i=0; i<MAX_PROGRAM_NAME && name[i]; i++)
    {
        thread->name[i]=name[i];
    }
    thread->status=ProgramStatus::READY;
    thread->priority=priority;
    thread->ticks=priority*10;
    thread->ticksPassedBy=0;
    thread->pid=((int)thread - (int)PCB_SET)/PCB_SIZE;
    //线程栈
    thread->stack=(int*)((int)thread + PCB_SIZE);
    thread->stack -= 7;
    thread->stack[0]=0;
    thread->stack[1]=0;
    thread->stack[2]=0;
    thread->stack[3]=0;
    thread->stack[4]=(int)function;
    thread->stack[5]=(int)program_exit;
    thread->stack[6]=(int)parameter;
    allPrograms.push_back(&(thread->tagInAllList));
    readyPrograms.push_back(&(thread->tagInGeneralList));
    //恢复中断
    interruptManager.setInterruptStatus(status);
    return thread->pid;
}
PCB* ProgramManager::allocatePCB()
{
    for(int i=0; i<MAX_PROGRAM_AMOUNT; i++)
    {
        if(!PCB_SET_STATUS[i])
        {
            PCB_SET_STATUS[i]=true;
            return (PCB*)((int)PCB_SET + PCB_SIZE*i);
        }
    }
    return nullptr;
}  
void ProgramManager::releasePCB(PCB*  program)
{
    int index=((int)program- (int)PCB_SET)/PCB_SIZE;
    PCB_SET_STATUS[index]=false;
}
void ProgramManager::schedule()
{
    bool status=interruptManager.getInterruptStatus();
    interruptManager.disableInterrupt();
    if(readyPrograms.size()==0)
    {
        interruptManager.setInterruptStatus(status);
        return;
    }
    if(running->status==ProgramStatus::RUNNING)
    {
        running->status=ProgramStatus::READY;
        running->ticks=running->priority*10;
        readyPrograms.push_back(&(running->tagInGeneralList));
    }else if(running->status==ProgramStatus::DEAD){
        releasePCB(running);
    }
    ListItem* item=readyPrograms.front();
    PCB* next=ListItemToPCB(item,tagInGeneralList);
    PCB* cur=running;
    next->status=ProgramStatus::RUNNING;
    running=next;
    readyPrograms.pop_front();

    asm_switch_thread(cur,next);
    interruptManager.setInterruptStatus(status);
}
void program_exit()
{
    PCB* thread=programManager.running;
    thread->status=ProgramStatus::DEAD;
    if(thread->pid)
    {
        programManager.schedule();
    }else{
        interruptManager.disableInterrupt();
        printf("halt...\n");
        asm_halt();
    }
}
